Analyser les projets TypeScript avec Moose

Ce tutoriel vous expliquera une démarche pour importer dans Moose un modèle d’un projet TypeScript et d’en faire une analyse.

Auteur·rice·s

Christopher Fuhrman

Logo ETS

Date de publication

14 janvier 2025 à 16:53:34 +00:00

Introduction

Ce tutoriel explique comment analyser des projets TypeScript avec Moose dans le cadre du cours MGL843 à l’ÉTS. Il s’inspire du tutoriel Analyzing Java with Moose 8.

Rappel des principes

a input Code source TypeScript (*.ts) à analyser ts2famix ts2famix input->ts2famix model modèle (json) ts2famix->model moose Moose (Pharo) model->moose analyse Analyse moose->analyse mm Métamodèle FamixTypeScript mm->ts2famix mm->model mm->moose

Les principes importants de ce tutoriel sont illustrés dans la figure ci-dessus. Nous les explorerons à différentes étapes du tutoriel. Le but est de vous guider à travers ces étapes, qui représentent un processus de base pour effectuer une analyse (empirique) dans le cadre du cours.

Obtenir le code source d’un projet TypeScript à analyser

a input Code source TypeScript (*.ts) à analyser

  • Trouvez un projet en TypeScript à analyser, par exemple sur https://github.com/Chuzzy/Emojiopoly.
  • Clonez le projet avec Git pour obtenir le code sur votre machine locale, par exemple dans le répertoire GitHub/Emojiopoly.

Installer l’importateur ts2famix

a ts2famix ts2famix

  • ts2famix est un logiciel pour node.js. Installer node et npm
  • Ouvrez un terminal Git Bash dans VS Code.
    • ⚠ Utilisez un environnement de commande Git Bash (même sur Windows).
    • ⚠ VS Code sur Windows démarre un terminal avec Powershell. Pour ce tutoriel, vous devez avoir un terminal Git Bash. Consultez comment spécifier un autre terminal shell dans VS Code.
    • Les commandes Bash sont similaires à des commandes dans Linux : ls, cd, etc.
    • Les chemins du système de fichiers sont formatés comme sous Linux, ce qui signifie que vous devez utiliser la barre oblique (/) au lieu de la barre oblique inverse (\, utilisée sous Windows) dans les chemins.
    • ts2famix est une bibliothèque (package) npm. Installez node et npm.
  • Installez l’importateur ts2famix avec la commande npm install -g ts2famix dans le terminal Git Bash.

Générer un modèle du projet

a input Code source TypeScript (*.ts) à analyser ts2famix ts2famix input->ts2famix model modèle (json) ts2famix->model

  • Utilisez la même fenêtre Bash que celle utilisée précédemment pour installer l’outil ts2famix.

  • Si votre répertoire de travail actuel est le même que celui du projet, par exemple, GitHub/Emojiopoly, vous pouvez taper :

    ts2famix -i tsconfig.json -o emojiopoly-model.json

    Le fichier tsconfig.json est en fait GitHub/Emojiopoly/tsconfig.json (c’est dans le répertoire de travail). Ce fichier décrit le projet Emojiopoly (typiquement les projets TypeScript ont ce genre de fichier). ts2famix utilise ce fichier pour trouver le code source pour faire le modèle. Si votre projet n’a pas de tsconfig.json, il est toujours possible d’importer des fichiers avec l’option -i "/chemin/vers/fichiers/**/*.ts" (notez bien l’utilisation de " autour de l’expression  !) ce qui va trouver tous les fichiers *.ts dans l’arborescence spécifié avant le **/. Il s’agit d’un glob pattern pour spécifier des ensembles de fichiers à traiter. Le fichier emojiopoly-model.json est le modèle Famix (en format JSON) du projet TypeScript généré par l’importateur. Dans les étapes suivantes, vous allez charger ce modèle dans Moose.

Configurer l’image Moose (survol)

a moose Moose (Pharo)

Il y a plusieurs étapes à suivre pour importer un modèle dans Moose. Une fois cette étape terminée, vous pourrez réutiliser l’image pour effectuer des analyses.

  1. Créez une image Moose avec Pharo Launcher. Pour la version actuelle de ts2famix, il faut utiliser le template Moose Suite 11 (stable).
  2. Chargez le métamodèle FamixTypeScript dans Moose.

Créer une image Moose Suite 10 dans Pharo

  • Installez Pharo Launcher et lancez-le.
  • Ajoutez une image à partir du template Moose Suite 11 (stable). ## Charger le métamodèle FamixTypeScript dans Moose

a moose Moose (Pharo) mm Métamodèle FamixTypeScript mm->moose

Par défaut, Moose ne possède pas de métamodèle pour le langage TypeScript. Vous devez donc charger le métamodèle FamixTypeScript dans Moose.

Charger avec un script Baseline

  • Sélectionnez l’image Moose Suite 11 (stable) (créée à l’étape précédente) dans Pharo Launcher et démarrez-la (bouton Launch).

  • Dans Pharo, tapez CTRL-O CTRL-W pour ouvrir une fenêtre Moose Playground.

  • Dans cette fenêtre, tapez (collez) le texte suivant :

    Metacello new 
        githubUser: 'fuhrmanator' project: 'FamixTypeScript' commitish: 'master' path: 'src';
        baseline: 'FamixTypeScript';
        load
  • Appuyez sur CTRL-SHIFT-G (Do it all and go) pour exécuter la commande. Le métamodèle devrait être chargé à la fin.

Charger le modèle du projet TypeScript dans Moose

a model modèle (json) moose Moose (Pharo) model->moose

Maintenant que Moose connaît le métamodèle FamixTypeScript, vous pouvez charger un modèle de programme TypeScript créé par l’outil ts2famix.

  • Vous pouvez faire glisser le fichier emojiopoly-model.json et le déposer dans la fenêtre où s’exécute Moose 11. Une boîte de dialogue s’ouvrira pour vous demander de confirmer que vous souhaitez importer le modèle dans Moose. Faire glisser et déposer le fichier modèle dans Moose 11
  • Menu Moose > Models browser pour vérifier que le modèle est chargé dans Moose. Le nom emojiopoly-model (ou le nom du fichier .json) devrait être dans la liste de Models de la fenêtre.

Facultatif : automatiser le chargement d’un modèle

Pour automatiser le chargement du modèle dans Moose, vous pouvez utiliser le code suivant en Pharo.

'emojiopoly-model.json' asFileReference readStreamDo:
      [ :stream | model := FamixTypeScriptModel new
        importFromJSONStream: stream. model install ].

Effectuer une analyse

Cette étape n’est pas une analyse empirique complète, car il n’y a pas de questions de recherche ou de validation d’hypothèses, etc. Cependant, vous pouvez apprendre comment accéder aux informations dans un modèle de programme TypeScript à travers Moose.

a model modèle (json) moose Moose (Pharo) model->moose analyse Analyse moose->analyse

  • À partir de la fenêtre Models browser, sélectionnez emojiopoly-model dans la liste.
  • Cliquez sur le bouton Inspect (icône avec des lunettes).
  • Une nouvelle fenêtre Moose Inspector apparaîtra.
  • Cliquez sur Card dans la liste de gauche.
  • Vous verrez une sous-fenêtre a FamixTypeScriptClass (Card) à gauche.
  • Cliquez sur l’onglet SourceText en haut de cette sous-fenêtre pour voir le code source de la classe.
  • Cliquez sur l’onglet Moose Properties pour voir les propriétés Moose de cette classe.

Animation de Moose pour inspecter un modèle

Faire une requête simple

Dans une fenêtre Playground, exécutez le code suivant :

"Get the emojiopoly model (first in Moose panel)"
tsModel := MooseModel root first.
"Find all classes that have 100 or more lines of code"
bigClasses := tsModel allModelClasses 
    select: [ :each | 
        each numberOfLinesOfCode >= 100 ]

Le résultat devrait généralement inclure une seule classe, MonopolyGame. Vous pouvez la sélectionner et consulter son code source pour vérifier.

Dans l’onglet Navigation, vous pouvez également voir ses méthodes, ses attributs, etc.

Pour obtenir une liste de méthodes longues (contenant 20 lignes ou plus) dans le projet, exécutez ce script :

"Get the emojiopoly model (first in Moose panel)"
tsModel := MooseModel root first.
"Find all methods that have 20 or more lines of code"
longMethods := tsModel allMethods 
    select: [ :each | 
        each numberOfLinesOfCode >= 20 ]

Pour trouver la classe à laquelle chaque méthode appartient, consultez la propriété parentType dans la navigation.

Requêtes spécifiques à TypeScript

Que faire si vous souhaitez trouver tous les Decorators (un élément spécifique à TypeScript) dans un projet ? Malheureusement, il n’existe pas (encore) de méthode tsModel allDecorators pour les modèles TypeScript. La solution consiste à utiliser tsModel allMatching: FamixTypeScriptDecorator. En effet, la méthode allMatching: permet de trouver tous les éléments d’une entité spécifique. Vous pouvez voir les noms des éléments du métamodèle TypeScript dans la visualisation SVG du dépôt du métamodèle. Les éléments sont affichés comme des classes UML en bleu clair, par exemple, Module, Decorator, etc. Notez que vous devez ajouter le préfixe FamixTypeScript au nom de l’élément, par exemple, FamixTypeScriptModule, FamixTypeScriptDecorator, etc.

Faire une visualisation des classes avec Roassal 3

Roassal 3 est une bibliothèque de visualisation puissante (et complexe) dans Pharo. Vous pouvez vous inspirer d’une visualisation en Roassal (une bibliothèque de visualisation dans Pharo) pour représenter visuellement les classes dans un modèle Moose :

"La variable classes contient les classes que nous souhaitons visualiser"
classes := MooseModel root first allModelClasses.
"Un canvas est un conteneur de formes graphiques"
c := RSCanvas new.
"Chaque classe est représentée comme une boîte"
classes do: [ :aClass | c add: (RSBox new model: aClass) ].
"La largeur de chaque classe indique le nombre de variables définies dans la classe"
RSNormalizer width shapes: c shapes; from: 6; to: 20;
    normalize: #numberOfAttributes.
"La hauteur de chaque classe représente le nombre de méthodes"
RSNormalizer height shapes: c shapes; normalize: #numberOfMethods.
"La couleur d'une classe passe du gris au rouge, indiquant le nombre de lignes de code"
RSNormalizer color shapes: c shapes;
    from: Color gray; to: Color red; normalize: #numberOfLinesOfCode.
"Les lignes verticales indiquent la relation d'héritage"
RSLineBuilder orthoVertical
    canvas: c; withVerticalAttachPoint; color: Color lightGray;
    connectFrom: #superclass.
"Utiliser une disposition en arbre pour localiser adéquatement les classes"
RSTreeLayout on: c nodes.
"Nous rendons toutes les classes déplaçables et avec une fenêtre contextuelle"
c nodes @ RSDraggable @ RSPopup.
"La visualisation entière est zoomable, déplaçable, et les formes peuvent être recherchées"
c @ RSCanvasController.

Cette visualisation représente les classes sous forme de rectangles. Chaque rectangle a trois dimensions :

  • La couleur de chaque rectangle représente le nombre de lignes de code. Le gris signifie un nombre relativement faible de lignes de code, tandis que le rouge indique un nombre relativement élevé de lignes de code. La variation de couleur est gérée par la classe RSNormalizer.
  • La hauteur de chaque rectangle représente le nombre de méthodes.
  • La largeur de chaque rectangle représente le nombre d’attributs.
Astuce

La visualisation obtient les données de chaque élément Moose à travers les propriétés, par exemple #numberOfAttributes, #numberOfMethods et #numberOfLinesOfCode. Au fait, ce sont des méthodes (accesseurs) des éléments Famix, par exemple FamixTypeScriptClass qui fournissent les valeurs. On peut trouver d’autres propriétés dans l’onglet Moose Properties de ces éléments.

Visualisation du modèle Moose du projet Emojiopoly

Avec le projet emojiopoly, on voit bien que la classe MonopolyGame a beaucoup de méthodes (sa hauteur) et aussi beaucoup de lignes de code (sa couleur rouge).

Astuce

La syntaxe avec le dièse utilisée à la ligne 9, normalize: #numberOfAttributes, est un raccourci syntaxique pour une expression de bloc plus longue : normalize: [:element | element numberOfAttributes ]. Parfois, vous voudrez effectuer un calcul sur la valeur utilisée dans la visualisation, par exemple en la combinant avec un autre attribut comme le nombre de receivingInvocations. Dans ce cas, vous feriez normalize: [:element | element numberOfAttributes + element receivingInvocations size ].

La disposition (RSTreeLayout) permet également de visualiser la hiérarchie des classes en ce qui concerne l’héritage. Cependant, le projet emojiopoly n’utilise pas l’héritage en TypeScript, donc aucune arborescence n’est visible dans la visualisation.

Conclusion

Vous avez effectué les étapes nécessaires pour analyser des programmes en TypeScript à l’aide de l’outil Moose dans Pharo, en utilisant un métamodèle Famix et un importateur (ts2famix).

Il est important de comprendre que le métamodèle influence également d’autres éléments du processus, notamment l’importateur et le fichier .json qu’il génère (le modèle).

a ts2famix ts2famix model modèle (json) mm Métamodèle FamixTypeScript mm->ts2famix mm->model

L’importateur ts2famix dépend du métamodèle FamixTypeScript, car il transforme un programme TypeScript en modèle Famix, selon la structure du métamodèle.